﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using FBEntities.FBObjects;
using System.Drawing;
using System.Windows.Forms;
using XFItemControls.XFPanels.XFPanelItems;
using System.Threading;

namespace XFControls.XFPanels.XFPanelItems
{
    enum XFItemPostSelected
    {
        Profile,
        Comment,
        Like
    }

    enum XFItemPostType
    {
        link,
        photo,
        status,
        video,
        music,
        swf,
        comment
    }

    public class XFItemPost : IXFItemReceiveClick
    {
        private int _pictureWidth = 45;
        private int _height;
        private Rectangle commentsRec;
        private Rectangle likesRec;
        private XFItemPostSelected clicked;
        private XFItemPostType _postType;

        public XFItemType ItemType { get; set; }

        public XFItemStyle Style { get; set; }

        public Bitmap Buffer { get; set; }

        public FBPost Post { get; set; }

        public XFItemPost(FBPost post)
        {
            Post = post;
            _height = -1;

            Style = new XFItemStyle()
            {
                TextFont = new Font(FontFamily.GenericSansSerif, 8, FontStyle.Regular),
                TextColor = Color.Black,
                DashStyleBottom = System.Drawing.Drawing2D.DashStyle.Solid,
                BoarderBottomColor = Color.DarkGray,
                Padding = 5
            };

            if (Post != null && post.type == "comment")
                Style.BackgroundColor = Color.LightGray;

            Post.Updated += (o, e) =>
            {
                var par = Parent as XFPanelList;
                ResetHeight();
                if (Buffer != null)
                    Buffer.Dispose();

                Buffer = null;
                par.ClearAnimationItem(this);

                if (!par.IsDisposed && par.InvokeRequired)
                    par.Invoke(new Action(() =>
                    {
                        par.Invalidate();
                    }));
            };

            ItemType = XFItemType.ClickableNonChange;
            _postType = (XFItemPostType)Enum.Parse(_postType.GetType(), Post.type, true);
        }

        #region IXFItem Members

        public XFPanelBase Parent { get; set; }

        public XFItemState State { get; set; }

        public int GetHeight()
        {
            if (Post == null)
                return _pictureWidth + Style.PaddingTop + Style.PaddingBottom;

            if (_height > 0)
                return _height;

            int width = Screen.PrimaryScreen.WorkingArea.Width;
            int currX = Style.PaddingLeft + _pictureWidth;
            int currY = Style.PaddingTop;

            if (Parent != null)
            {
                width -= Parent.AlphaBarWidth;

                if (Parent.ScrollbarVisible)
                    width -= 5;
            }

            using (Bitmap b = new Bitmap(10, 10))
            using (Graphics g = Graphics.FromImage(b))
            {
                switch (_postType)
                {
                    case XFItemPostType.comment:
                    case XFItemPostType.status:
                        currY = XFItemPostUtils.ItemGetMessageHeight(this, g, 0, 0, width, Style, Post, ref commentsRec, ref likesRec);
                        break;
                    case XFItemPostType.video:
                    case XFItemPostType.music:
                    case XFItemPostType.photo:
                        currY = XFItemPostUtils.ItemGetPicturesHeight(this, g, 0, 0, width, Style, Post, ref commentsRec, ref likesRec);
                        break;
                    case XFItemPostType.link:
                    case XFItemPostType.swf:
                        currY = XFItemPostUtils.ItemGetMessageHeight(this, g, 0, 0, width, Style, Post, ref commentsRec, ref likesRec);
                        break;
                }
            }

            _height = currY + Style.PaddingBottom;

            if (Parent is XFPanelList)
                ((XFPanelList)Parent).Resize();

            return _height;
        }

        public void ResetHeight()
        {
            _height = -1;
        }

        public void ItemPaint(Graphics g, int x, int y)
        {
            int width = Screen.PrimaryScreen.WorkingArea.Width;

            XFControlUtils.DrawBackground(Style, g, x, y, width, _height);
            XFControlUtils.DrawBoarders(Style, g, x, y, width, _height);

            if (Parent != null)
            {
                width -= Parent.AlphaBarWidth;

                if (Parent.ScrollbarVisible)
                    width -= 5;
            }

            switch (_postType)
            {
                case XFItemPostType.comment:
                case XFItemPostType.status:
                    XFItemPostUtils.ItemPaintMessage(this, g, x, y, width, Style, Post, ref commentsRec, ref likesRec);
                    break;
                case XFItemPostType.video:
                case XFItemPostType.music:
                case XFItemPostType.photo:
                    XFItemPostUtils.ItemPaintPictures(this, g, x, y, width, Style, Post, ref commentsRec, ref likesRec);
                    break;
                case XFItemPostType.link:
                case XFItemPostType.swf:
                    XFItemPostUtils.ItemPaintMessage(this, g, x, y, width, Style, Post, ref commentsRec, ref likesRec);
                    break;
            }
        }

        public XFItemClickResult GetClickResult()
        {
            switch (clicked)
            {
                case XFItemPostSelected.Like:
                    {
                        var modal = Parent.ShowModal(XFModal.Bottom, "Do you want to Like this post?");

                        modal.OnSuccessAction += (o, e) =>
                        {
                            var par = Parent as XFPanelList;
                            int loc = par[this];

                            XFWorkerPostLike worker = new XFWorkerPostLike(Post, false);
                            XFItemLoading loading = new XFItemLoading(worker, false);

                            XFItemAnimation loadingAnimation = new XFItemAnimation(GetHeight(), likesRec.X + Style.PaddingLeft + 15, likesRec.Y + Style.PaddingTop + 25);
                            loadingAnimation.SetStoryLine(XFControlUtils.GetCurrent_Directory() + "\\Resources\\loading.png", 8);
                            par.AddAnimation(loadingAnimation, this);

                            loading.WorkFinished += (ob, ex) => { };

                            par.Add(loading, loc);
                            loading.DoWork();
                        };
                        modal.State = XFControls.XFPanels.XFPanelModals.XFModalState.Expanding;
                    }
                    return XFItemClickResult.CustomModal;
                case XFItemPostSelected.Comment:
                    {
                        if (Parent == null)
                            return XFItemClickResult.Nothing;

                        var rp = new XFPanelList();
                        var back = new XFItemBack();

                        rp.Add(new XFItemPost(Post));
                        XFWorkerLoadComments worker = new XFWorkerLoadComments(Post);
                        XFItemLoading loading = new XFItemLoading(worker);

                        loading.WorkFinished += (o, e) =>
                        {
                            FBPost parsedPost = null;
                            if (e.Worker is XFWorkerLoadComments)
                                parsedPost = ((XFWorkerLoadComments)e.Worker).ParsedPost;

                            var par = ((XFItemLoading)o).Parent as XFPanelList;

                            if (!par.IsDisposed)
                                par.Invoke(new Action(() =>
                                {
                                    par.Add(new XFItemAddComment(parsedPost));
                                    foreach (var p in parsedPost.Comments.data)
                                    {
                                        XFItemPost post = new XFItemPost(p.ToPost());
                                        par.Add(post);
                                    }
                                }));
                        };

                        rp.Add(loading);

                        rp.AddHeaderItem(back);
                        Parent.SetRightPanel(rp);

                        rp.ShowAlphaBar(false);
                        rp.ShowScrollbar(true);
                        rp.ScrollbarColor = Parent.ScrollbarColor;

                    }
                    break;
                case XFItemPostSelected.Profile:
                    {
                        if (Parent == null)
                            return XFItemClickResult.Nothing;

                        var friendProf = Post.from.ToPerson();
                        //friendProf.Parse();

                        var rp = XFItemControlUtils.SetupProfile(friendProf);
                        rp.PanelName = friendProf.name;

                        var back = new XFItemBack();

                        rp.AddHeaderItem(back);
                        Parent.SetRightPanel(rp);

                        rp.ShowAlphaBar(false);
                        rp.ShowScrollbar(true);

                    }
                    break;
            }


            return XFItemClickResult.SlideLeft;
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (Buffer != null)
                Buffer.Dispose();
            Buffer = null;
            if (Style != null)
                Style.Dispose();
            Style = null;
        }

        #endregion

        #region IXFItemReceiveClick Members

        public void GetClick(int x, int y)
        {
            if (commentsRec.Contains(new Point(x, y)))
                clicked = XFItemPostSelected.Comment;

            else if (likesRec.Contains(new Point(x, y)))
                clicked = XFItemPostSelected.Like;

            else if (x < _pictureWidth + (Style.PaddingLeft * 2))
                clicked = XFItemPostSelected.Profile;

            else clicked = XFItemPostSelected.Comment;
        }

        #endregion
    }

    class XFItemPostUtils
    {
        private static int _pictureWidth = 45;
        private static int _lineSpace = 5;

        public static int ItemGetMessageHeight(XFItemPost xFItemPost, Graphics g, int x, int y, int width, XFItemStyle Style, FBPost Post, ref Rectangle commentsRec, ref Rectangle likesRec)
        {
            int currX = x + (Style.PaddingLeft * 2) + _pictureWidth;
            int currY = y + Style.PaddingTop;

            width -= _pictureWidth + (Style.PaddingLeft * 2) + Style.PaddingRight;

            writeFromTo(Post, Style, currX, ref currY, width, g);
            writeMessage(Post, Style, currX, ref currY, width, g);
            writePostTime(Post, Style, currX, ref currY, g);
            drawActions(Post, Style, currX, ref currY, g, ref commentsRec, ref likesRec);

            return currY;
        }

        public static int ItemGetPicturesHeight(XFItemPost item, Graphics g, int x, int y, int width, XFItemStyle Style, FBPost Post, ref Rectangle commentsRec, ref Rectangle likesRec)
        {
            int currX = x + (Style.PaddingLeft * 2) + _pictureWidth;
            int currY = y + Style.PaddingTop;

            width -= _pictureWidth + (Style.PaddingLeft * 2) + Style.PaddingRight;

            writeFromTo(Post, Style, currX, ref currY, width, g);
            writeName(Post, Style, currX, ref currY, width, g);
            writeMessage(Post, Style, currX, ref currY, width, g);
            getPictureHeight(ref currY, item);
            writePostTime(Post, Style, currX, ref currY, g);
            drawActions(Post, Style, currX, ref currY, g, ref commentsRec, ref likesRec);

            return currY;
        }

        public static int ItemPaintMessage(XFItemPost item, Graphics g, int x, int y, int width, XFItemStyle Style, FBPost Post, ref Rectangle commentsRec, ref Rectangle likesRec)
        {
            int currX = x + (Style.PaddingLeft * 2) + _pictureWidth;
            int currY = y + Style.PaddingTop;

            width -= _pictureWidth + (Style.PaddingLeft * 2) + Style.PaddingRight;

            drawPosterImage(item, g, Style, Post);
            writeFromTo(Post, Style, currX, ref currY, width, g);
            writeMessage(Post, Style, currX, ref currY, width, g);
            writePostTime(Post, Style, currX, ref currY, g);
            drawActions(Post, Style, currX, ref currY, g, ref commentsRec, ref likesRec);

            return currY;
        }

        public static int ItemPaintPictures(XFItemPost item, Graphics g, int x, int y, int width, XFItemStyle Style, FBPost Post, ref Rectangle commentsRec, ref Rectangle likesRec)
        {
            int currX = x + (Style.PaddingLeft * 2) + _pictureWidth;
            int currY = y + Style.PaddingTop;

            width -= _pictureWidth + (Style.PaddingLeft * 2) + Style.PaddingRight;

            drawPosterImage(item, g, Style, Post);
            writeFromTo(Post, Style, currX, ref currY, width, g);
            writeName(Post, Style, currX, ref currY, width, g);
            writeMessage(Post, Style, currX, ref currY, width, g);
            drawPictures(item, Post, Style, currX, ref currY, width, g);
            writePostTime(Post, Style, currX, ref currY, g);
            drawActions(Post, Style, currX, ref currY, g, ref commentsRec, ref likesRec);

            return currY;
        }

        private static void drawPosterImage(XFItemPost item, Graphics g, XFItemStyle Style, FBPost Post)
        {
            string url = "";

            if (!String.IsNullOrEmpty(Post.icon))
                url = Post.icon;
            else
                url = Post.from.ToPerson().Picture.url;

            item.DrawIcon(url, g, new Rectangle(Style.PaddingLeft, Style.PaddingTop, _pictureWidth, _pictureWidth));
        }

        private static void writeFromTo(FBPost Post, XFItemStyle Style, int currX, ref int currY, int width, Graphics g)
        {
            int finalY = currY;
            using (SolidBrush b = new SolidBrush(Color.Navy))
            using (Font f = new Font(Style.TextFont.Name, Style.TextFont.Size + 1, FontStyle.Bold))
            {
                if (Post != null)
                {
                    g.DrawString(Post.from.name, f, b, currX, currY);
                    var mes = g.MeasureString(Post.from.name, f);
                    finalY += (int)mes.Height + _lineSpace;
                    currX += (int)mes.Width + _lineSpace;
                }
            }

            if (Post.to != null && Post.to.data.Count > 0)
            {
                string arrow = ">";
                string totalDisplay = "";
                using (SolidBrush b = new SolidBrush(Color.Black))
                    g.DrawString(arrow, Style.TextFont, b, currX, currY);

                currX += (int)g.MeasureString(arrow, Style.TextFont).Width + _lineSpace;
                for (int i = 0; i < Post.to.data.Count; i++)
                {
                    var to = Post.to.data[i];
                    string display = to.name;
                    if (i > Post.to.data.Count - 1)
                        display += ", ";

                    using (SolidBrush b = new SolidBrush(Color.Navy))
                    {
                        if (Post != null)
                        {
                            Font f = new Font(Style.TextFont.Name, Style.TextFont.Size + 1, FontStyle.Bold);

                            var mes = g.MeasureString(display, f);
                            int tempX = currX + (int)mes.Width;

                            if (tempX > width)
                            {
                                if (string.IsNullOrEmpty(totalDisplay) && currX < width)
                                    g.DrawString(XFControlUtils.EllipsisWord(width - currX, display, f), f, b, currX, currY);

                                f.Dispose();
                                break;
                            }

                            g.DrawString(display, f, b, currX, currY);
                            currX = tempX;
                            totalDisplay += display;
                            f.Dispose();
                        }
                    }
                }
            }

            currY = finalY;
        }

        private static void writeName(FBPost Post, XFItemStyle Style, int currX, ref int currY, int width, Graphics g)
        {
            using (SolidBrush b = new SolidBrush(Style.TextColor))
            {

                if (Post == null || string.IsNullOrEmpty(Post.name)) { }
                else
                {
                    string txt = XFControlUtils.GetSizedString(width, Post.name, Style.TextFont);
                    XFControlUtils.DrawJustifiedString(g, currX, currY, width, txt, Style.TextFont, b.Color, false);

                    int mes = (int)g.MeasureString(txt, Style.TextFont).Height;
                    currY += mes + _lineSpace;
                }
            }
        }

        private static void writeMessage(FBPost Post, XFItemStyle Style, int currX, ref int currY, int width, Graphics g)
        {
            using (SolidBrush b = new SolidBrush(Style.TextColor))
            {

                if (Post == null || string.IsNullOrEmpty(Post.message)) { }
                else
                {
                    string txt = XFControlUtils.GetSizedString(width, Post.message, Style.TextFont);
                    //XFControlUtils.DrawJustifiedString(g, currX, currY, width, txt, Style.TextFont, b.Color, false);
                    g.DrawString(txt, Style.TextFont, b, currX, currY);

                    int mes = (int)g.MeasureString(txt, Style.TextFont).Height;
                    currY += mes + _lineSpace;
                }
            }
        }

        private static void drawPictures(XFItemPost item, FBPost Post, XFItemStyle Style, int currX, ref int currY, int width, Graphics g)
        {
            if (!string.IsNullOrEmpty(Post.link))
            {
                item.DrawImage(Post.picture, g, new Rectangle(currX, currY, _pictureWidth, _pictureWidth), true);
            }
        }

        private static void getPictureHeight(ref int currY, XFItemPost item)
        {
            currY += (_pictureWidth * 2) + _lineSpace;
        }

        private static void writePostTime(FBPost Post, XFItemStyle Style, int currX, ref int currY, Graphics g)
        {
            using (SolidBrush b = new SolidBrush(Color.DarkSlateGray))
            {
                DateTime startTime = DateTime.UtcNow;
                DateTime endTime = Post.created_time;
                TimeSpan span = startTime.Subtract(endTime);

                string display = "";
                if (span.Days > 0)
                {
                    display = span.Days == 1 ? span.Days + " Day ago" : span.Days + " Days ago";
                }
                else if (span.Hours > 0)
                {
                    display = span.Hours == 1 ? span.Hours + " Hour ago" : span.Hours + " Hours ago";
                }
                else if (span.Minutes > 0)
                {
                    display = span.Minutes == 1 ? span.Minutes + " Minute ago" : span.Minutes + " Minutes ago";
                }
                else if (span.Seconds > 0)
                {
                    display = span.Seconds == 1 ? span.Seconds + " Second ago" : span.Seconds + " Seconds ago";
                }
                else
                {
                    display = "Moments ago";
                }

                Font f = new Font(Style.TextFont.Name, Style.TextFont.Size - 1, FontStyle.Bold);

                g.DrawString(display, f, b, currX, currY);
                currY += _lineSpace + (int)g.MeasureString(display, f).Height;
            }
        }

        private static void drawActions(FBPost Post, XFItemStyle Style, int currX, ref int currY, Graphics g, ref Rectangle commentsRec, ref Rectangle likesRec)
        {
            using (SolidBrush b = new SolidBrush(Color.Navy))
            {
                if (Post != null && Post.type != "comment")
                {
                    currX += _pictureWidth;
                    Font f = new Font(Style.TextFont.Name, Style.TextFont.Size + (float)0.5, FontStyle.Bold);
                    var mes = g.MeasureString("Comments", f);

                    string comments = "";

                    if (Post.comments == null)
                        comments = "(0)Comments";
                    else if (Post.comments.count == 1)
                        comments = string.Format("({0})Comment", Post.comments.count);
                    else
                        comments = string.Format("({0})Comments", Post.comments.count);

                    string likes = "";
                    if (Post.likes == 1)
                        likes = string.Format("({0})Like", Post.likes);
                    else
                        likes = string.Format("({0})Likes", Post.likes);

                    var mesActCom = g.MeasureString(comments, f);
                    var mesActLikes = g.MeasureString(likes, f);

                    bool expand = false;
                    if (Post.actions.Any(p => p.name == "Comment"))
                    {
                        expand = true;
                        commentsRec = new Rectangle(currX - 10, currY - 10, (int)mesActCom.Width + 20, (int)mesActCom.Height + 20);
                        g.DrawString(comments, f, b, currX, currY);
                    }
                    if (Post.actions.Any(p => p.name == "Like"))
                    {
                        expand = true;
                        likesRec = new Rectangle(currX + (int)mes.Width + currX - 10, currY - 20, (int)mesActLikes.Width + 20, (int)mesActLikes.Height + 20);
                        g.DrawString(likes, f, b, currX + mes.Width + currX, currY);
                    }

                    if (expand)
                        currY += (int)mes.Height + _lineSpace;

                    f.Dispose();
                }
            }
        }
    }
}
